package gdconf

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"server_cluster/common/tools"
	"strconv"
	"strings"
	"time"
)

// 自定义CSV类型相关

func splitStringArray(str string) []string {
	if str == "" {
		return make([]string, 0)
	} else if strings.Contains(str, ";") {
		return strings.Split(str, ";")
	} else if strings.Contains(str, "|") {
		return strings.Split(str, "|")
	} else {
		return []string{str}
	}
}

type IntArray []int32

func (a *IntArray) UnmarshalCSV(data []byte) error {
	intStrList := splitStringArray(string(data))
	for _, intStr := range intStrList {
		v, err := strconv.ParseInt(intStr, 10, 32)
		if err != nil {
			panic(err)
		}
		*a = append(*a, int32(v))
	}
	return nil
}

func (a *IntArray) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), a)
	return err
}

func (a IntArray) Value() (driver.Value, error) {
	data, err := json.Marshal(a)
	return string(data), err
}

type IntArrayArray [][]int32

func (a *IntArrayArray) UnmarshalCSV(data []byte) error {
	intArrayStrList := strings.Split(string(data), ";")
	for _, intArrayStr := range intArrayStrList {
		intStrList := strings.Split(intArrayStr, "|")
		intList := make([]int32, 0)
		for _, intStr := range intStrList {
			v, err := strconv.ParseInt(intStr, 10, 32)
			if err != nil {
				panic(err)
			}
			intList = append(intList, int32(v))
		}
		*a = append(*a, intList)
	}
	return nil
}

func (a *IntArrayArray) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), a)
	return err
}

func (a IntArrayArray) Value() (driver.Value, error) {
	data, err := json.Marshal(a)
	return string(data), err
}

type Item struct {
	ItemId    int32
	ItemCount int32
}

func (i *Item) UnmarshalCSV(data []byte) error {
	var a IntArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	i.ItemId = a[0]
	i.ItemCount = a[1]
	return nil
}

func (i *Item) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), i)
	return err
}

func (i Item) Value() (driver.Value, error) {
	data, err := json.Marshal(i)
	return string(data), err
}

type ItemList []*Item

func (i *ItemList) UnmarshalCSV(data []byte) error {
	var a IntArrayArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	for _, aa := range a {
		*i = append(*i, &Item{
			ItemId:    aa[0],
			ItemCount: aa[1],
		})
	}
	return nil
}

func (i *ItemList) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), i)
	return err
}

func (i ItemList) Value() (driver.Value, error) {
	data, err := json.Marshal(i)
	return string(data), err
}

type FightProp struct {
	PropId    int32
	PropValue int32
}

func (f *FightProp) UnmarshalCSV(data []byte) error {
	var a IntArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	f.PropId = a[0]
	f.PropValue = a[1]
	return nil
}

func (f *FightProp) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), f)
	return err
}

func (f FightProp) Value() (driver.Value, error) {
	data, err := json.Marshal(f)
	return string(data), err
}

type FightPropList []*FightProp

func (f *FightPropList) UnmarshalCSV(data []byte) error {
	var a IntArrayArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	for _, aa := range a {
		*f = append(*f, &FightProp{
			PropId:    aa[0],
			PropValue: aa[1],
		})
	}
	return nil
}

func (f *FightPropList) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), f)
	return err
}

func (f FightPropList) Value() (driver.Value, error) {
	data, err := json.Marshal(f)
	return string(data), err
}

// 增加战斗属性类型
const (
	FightPropAddTypeValue   = 1 // 数值
	FightPropAddTypePercent = 2 // 百分比
)

type FightPropAdd struct {
	PropId    int32
	AddType   int32
	PropValue int32
}

func (f *FightPropAdd) UnmarshalCSV(data []byte) error {
	var a IntArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	f.PropId = a[0]
	f.AddType = a[1]
	f.PropValue = a[2]
	return nil
}

func (f *FightPropAdd) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), f)
	return err
}

func (f FightPropAdd) Value() (driver.Value, error) {
	data, err := json.Marshal(f)
	return string(data), err
}

type FightPropAddList []*FightPropAdd

func (f *FightPropAddList) UnmarshalCSV(data []byte) error {
	var a IntArrayArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	for _, aa := range a {
		*f = append(*f, &FightPropAdd{
			PropId:    aa[0],
			AddType:   aa[1],
			PropValue: aa[2],
		})
	}
	return nil
}

func (f *FightPropAddList) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), f)
	return err
}

func (f FightPropAddList) Value() (driver.Value, error) {
	data, err := json.Marshal(f)
	return string(data), err
}

type Time struct {
	time.Time
}

func (t *Time) UnmarshalCSV(data []byte) error {
	var tmp = tools.Str2timestamp(string(data))
	if tmp == -1 {
		return errors.New("parse time fail")
	}
	(*t).Time = tools.Timestamp2time(tmp)
	return nil
}

func (t *Time) Scan(value any) error {
	ts, err := strconv.ParseInt(string(value.([]byte)), 10, 64)
	if err != nil {
		return err
	}
	(*t).Time = time.Unix(ts, 0)
	return nil
}

func (t Time) Value() (driver.Value, error) {
	ts := strconv.FormatInt(t.Unix(), 10)
	return ts, nil
}

type TimeRange []*Time

func (t *TimeRange) UnmarshalCSV(data []byte) error {
	split := strings.Split(string(data), "|")
	if len(split) != 2 {
		return errors.New("time range format error")
	}
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		return err
	}
	t1, err := time.ParseInLocation("2006-01-02-15:04:05", split[0], loc)
	if err != nil {
		return err
	}
	t2, err := time.ParseInLocation("2006-01-02-15:04:05", split[1], loc)
	if err != nil {
		return err
	}
	*t = TimeRange{&Time{Time: t1}, &Time{Time: t2}}
	return nil
}

func (t *TimeRange) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), t)
	return err
}

func (t TimeRange) Value() (driver.Value, error) {
	data, err := json.Marshal(t)
	return string(data), err
}

type IdWeight struct {
	Id     int32
	Weight int32
}

func (i IdWeight) GetWeight() int32 {
	return i.Weight
}

type IdWeightList []*IdWeight

func (i IdWeightList) GetWeightSum() int32 {
	sum := int32(0)
	for _, idWeight := range i {
		sum += idWeight.Weight
	}
	return sum
}

func (i *IdWeightList) UnmarshalCSV(data []byte) error {
	var a IntArrayArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	for _, aa := range a {
		*i = append(*i, &IdWeight{
			Id:     aa[0],
			Weight: aa[1],
		})
	}
	return nil
}

func (i *IdWeightList) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), i)
	return err
}

func (i IdWeightList) Value() (driver.Value, error) {
	data, err := json.Marshal(i)
	return string(data), err
}

type IdNumWeight struct {
	Id     int32
	Num    int32
	Weight int16
}
type IdNumWeightList []*IdNumWeight

func (i *IdNumWeightList) UnmarshalCSV(data []byte) error {
	var a IntArrayArray = nil
	err := a.UnmarshalCSV(data)
	if err != nil {
		return err
	}
	for _, aa := range a {
		var weight = int16(0)
		if len(aa) < 3 {
			weight = 0
		} else {
			weight = int16(aa[2])
		}
		*i = append(*i, &IdNumWeight{
			Id:     aa[0],
			Num:    aa[1],
			Weight: weight,
		})
	}
	return nil
}

func (i *IdNumWeightList) Scan(value any) error {
	err := json.Unmarshal(value.([]byte), i)
	return err
}

func (i IdNumWeightList) Value() (driver.Value, error) {
	data, err := json.Marshal(i)
	return string(data), err
}
